import com.pbking.logging.Logger;
import com.pbking.util.eventHandling.*;

/**
 * @author Jason Crist
 */
class com.pbking.component.ComponentBase extends MovieClip implements IEventBroadcaster {
	
	// VARIABLES //////////
	
	private var _mode:String;
	private var _modeIsFrame:Boolean = true;
	private var doLaterArray:Array;
	private var refreshFlag:Boolean;
	private var doLaterFlag:Boolean;
	private var __width:Number;
	private var __height:Number;
	private var _enabled:Boolean = true;
	
	public var stopOnModeChange:Boolean = true;

	// GETTERS and SETTERS //////////
	
	public function get width():Number { return this.__width; }
	public function set width(newVal:Number):Void
	{
		this.__width = newVal;
		refresh();
	}
	
	public function get height():Number { return this.__height; }
	public function set height(newVal:Number):Void
	{
		this.__height = newVal;
		refresh();
	}
	
	public function get mode():String { return this._mode; }
	public function set mode(newVal:String): Void
	{
		this.setMode(newVal);
	}
	
	public function get enabled():Boolean { return this._enabled; }
	public function set enabled(newVal:Boolean):Void
	{
		this.setEnabled(newVal);
	}
	
	public function get visible():Boolean { return this._visible; }
	public function set visible(newVal:Boolean):Void
	{
		this.setVisible(newVal);
	}
	
	// CONSTRUCTION //////////

	public function ComponentBase()
	{
		EventBroadcaster.initialize(this);
		
		if(!__width) __width = this._width;
		if(!__height) __height = this._height;
		
		init();
		refresh(true);
		doLater(initChildren);
		doLater(creationComplete);
	}

	// PUBLIC FUNCTIONS //////////
	
	// EVENT FUNCTIONS

	public function addEventListener(eventType:String, target:Object, callback:Function, singleEvent:Boolean){}
	public function addSingleEventListener(eventType:String, target:Object, callback:Function){}
	public function removeEventListener(eventType:String, target:Object, callback:Function){}
	public function removeAllEventTypes(eventType:String){}
	public function removeAllEventTargets(target:Object){}
	public function removeAllEvents(){}
	public function dispatch(event:Event){}

	/**
	 * cause the component to jump to a given frame and dispatch an "onModeChange" event
	 */
	public function setMode(newMode:String){
		this._mode = newMode;
		if(_modeIsFrame){
			
			if(stopOnModeChange)
				this.gotoAndStop(this._mode);
			else
				this.gotoAndPlay(this._mode);
		}
				
		dispatch(new Event("onModeChange", this, newMode));
	}
	
	public function setEnabled(newVal:Boolean):Void
	{
		Logger.debug("Entry: " + newVal, "ComponentBase", "setEnabled");
		
		if(newVal != this._enabled)
		{
			this._enabled = newVal;
			dispatch(new Event("onEnabledChanged", this, this._enabled));
		}
	}
	
	public function setVisible(newVal:Boolean):Void
	{
		if(newVal != this._visible)
		{
			this._visible = newVal;
			dispatch(new Event("onVisibilityChanged", this, this._visible));
		}
	}
	
	/**
	 * Set the .width and .height of the component.  (This is different than the ._width and ._height)
	 */
	public function setSize(newWidth:Number, newHeight:Number):Void
	{
		this.__width = newWidth;
		this.__height = newHeight;
		refresh();
	}
	
	/**
	 * Que draw() to be called on the next frame
	 * if you pass TRUE draw is called immediately instead
	 */
	public function refresh(forceNow:Boolean){
		
		if(forceNow){
			refreshFlag = false;
			draw();
			return;
		}
		
		if(!refreshFlag){
			refreshFlag = true;
			doLater(draw);
		}
	}
	
	// PRIVATE FUNCTIONS //////////
	
	private function init(){}
	private function initChildren(){}	
	private function draw(){}
	
	private function creationComplete(){
		dispatch( new Event(Event.READY, this, null) );
	}
	
	// DOLATER FUNCTIONS
	
	/**
	 * Do the provided method on the next onEnterFrame
	 * Currently no paramaters can be set for this method
	 */
	private function doLater(doLaterFunction:Function){
		if(doLaterArray == null) doLaterArray = new Array();
		doLaterArray.push(doLaterFunction);
		if(!doLaterFlag){
			doLaterFlag = true;
			GlobalEventBroadcaster.getInstance().addSingleEventListener("onEnterFrame", this, doLaterDispatcher);
		}
	}
	
	/**
	 * Execute all of the events qued up by doLater()
	 */
	private function doLaterDispatcher(){
		//loop through all of the functions
		for(var i:Number=0; i<doLaterArray.length; i++){
			var f:Function = doLaterArray[i];
			
			//we're only executing draw if the refreshFlag is set
			if((f == draw && refreshFlag) || f != draw){
				//execute the function
				this["___doLaterFunction___"] = f;
				this["___doLaterFunction___"]();
			}
		}
		this["___doLaterFunction___"] = null;

		//clear the flags
		doLaterFlag = false;
		refreshFlag = false;
		doLaterArray = [];
	}
	
	//utility
	public function isMouseOver():Boolean{
		var result:Boolean = false;
		
		if( this._xmouse > 0 && this._xmouse < width && this._ymouse > 0 && this._ymouse < height )
		{
			result = true;	
		}
		
		return result;
	}
}